﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace g4
{
    /// <summary>
    /// 网格边界闭合类：用于闭合网格中的边界环（如孔洞），生成平整或自定义形状的填充面
    /// 核心流程：边界预处理 → 边界拉伸 → 填充 → 局部重网格化优化
    /// </summary>
    public class MeshLoopClosure
    {
        /// <summary>
        /// 目标网格（包含需要闭合的边界环）
        /// </summary>
        public DMesh3 Mesh;

        /// <summary>
        /// 初始边界环（需要闭合的边界或孔洞）
        /// </summary>
        public EdgeLoop InitialBorderLoop;

        /// <summary>
        /// 平面闭合的目标平面（定义闭合面的空间平面）
        /// </summary>
        public Frame3f FlatClosePlane;

        /// <summary>
        /// 目标边长度（用于控制填充区域的网格密度，0则自动计算）
        /// </summary>
        public double TargetEdgeLen = 0;

        /// <summary>
        /// 拉伸区域的三角形组ID（-1表示自动分配）
        /// </summary>
        public int ExtrudeGroup = -1;

        /// <summary>
        /// 填充区域的三角形组ID（-1表示自动分配）
        /// </summary>
        public int FillGroup = -1;


        /// <summary>
        /// 构造函数：初始化网格边界闭合器
        /// </summary>
        /// <param name="mesh">目标网格</param>
        /// <param name="border_loop">需要闭合的边界环</param>
        public MeshLoopClosure(DMesh3 mesh, EdgeLoop border_loop)
        {
            Mesh = mesh;
            InitialBorderLoop = border_loop;
        }


        /// <summary>
        /// 验证操作的合法性：检查边界环是否有效及网格是否有重复三角形
        /// </summary>
        /// <returns>验证状态（Ok表示合法）</returns>
        public virtual ValidationStatus Validate()
        {
            // 检查初始边界环是否为有效边界
            ValidationStatus loopStatus = MeshValidation.IsBoundaryLoop(Mesh, InitialBorderLoop);
            if (loopStatus != ValidationStatus.Ok)
                return loopStatus;

            // 检查网格是否包含重复三角形
            ValidationStatus meshStatus = MeshValidation.HasDuplicateTriangles(Mesh);
            if (meshStatus != ValidationStatus.Ok)
                return meshStatus;

            return ValidationStatus.Ok;
        }


        /// <summary>
        /// 执行边界闭合操作（默认使用平面闭合）
        /// </summary>
        /// <returns>操作是否成功</returns>
        public virtual bool Close()
        {
            Close_Flat();
            return true;
        }


        /// <summary>
        /// 平面闭合算法：将边界环拉伸到指定平面并填充，优化局部网格
        /// </summary>
        public void Close_Flat()
        {
            // 计算网格边长度统计信息（用于自动确定目标边长度）
            double minLen, maxLen, avgLen;
            MeshQueries.EdgeLengthStats(Mesh, out minLen, out maxLen, out avgLen, 1000);
            double targetEdgeLen = (TargetEdgeLen <= 0) ? avgLen : TargetEdgeLen;

            // 预处理边界环：局部重网格化，优化边界形状和拓扑
            List<int> refinedBorderEdges;
            cleanup_boundary(Mesh, InitialBorderLoop, avgLen, out refinedBorderEdges, 3);

            // 查找处理后的边界环（优先使用包含预处理边的环，否则用最大环）
            MeshBoundaryLoops loops = new MeshBoundaryLoops(Mesh);
            int loopIndex = loops.FindLoopContainingEdge(refinedBorderEdges[0]);
            if (loopIndex == -1)
                loopIndex = loops.MaxVerticesLoopIndex;
            EdgeLoop fillLoop = loops.Loops[loopIndex];

            // 分配三角形组ID（若未指定）
            int extrudeGroup = (ExtrudeGroup == -1) ? Mesh.AllocateTriangleGroup() : ExtrudeGroup;
            int fillGroup = (FillGroup == -1) ? Mesh.AllocateTriangleGroup() : FillGroup;

            // 拉伸边界环到目标平面
            MeshExtrudeLoop extrude = new MeshExtrudeLoop(Mesh, fillLoop);
            extrude.PositionF = (v, n, i) => {
                // 将拉伸后的顶点投影到目标平面
                return FlatClosePlane.ProjectToPlane((Vector3f)v, 1);
            };
            extrude.Extrude(extrudeGroup); // 执行拉伸操作
            MeshValidation.IsBoundaryLoop(Mesh, extrude.NewLoop); // 验证新边界

            Debug.Assert(Mesh.CheckValidity());

            // 平滑拉伸后的边界环（保持在目标平面上）
            MeshLoopSmooth loopSmooth = new MeshLoopSmooth(Mesh, extrude.NewLoop);
            loopSmooth.ProjectF = (v, i) => {
                return FlatClosePlane.ProjectToPlane((Vector3f)v, 1);
            };
            loopSmooth.Alpha = 0.5f; // 平滑系数
            loopSmooth.Rounds = 100; // 平滑迭代次数
            loopSmooth.Smooth();

            Debug.Assert(Mesh.CheckValidity());

            // 填充拉伸后的边界环（闭合孔洞）
            SimpleHoleFiller filler = new SimpleHoleFiller(Mesh, extrude.NewLoop);
            filler.Fill(fillGroup);

            Debug.Assert(Mesh.CheckValidity());

            // 选择需要重网格化的区域（拉伸和填充的三角形及其邻域）
            MeshFaceSelection remeshRoi = new MeshFaceSelection(Mesh);
            remeshRoi.Select(extrude.NewTriangles);
            remeshRoi.Select(filler.NewTriangles);
            remeshRoi.ExpandToOneRingNeighbours(); // 扩展到一环邻域
            remeshRoi.ExpandToOneRingNeighbours(); // 再次扩展
            remeshRoi.LocalOptimize(true, true);   // 局部优化选择区域
            int[] newRoi = remeshRoi.ToArray();

            // 清除拉伸区域的组ID（归为默认组）
            FaceGroupUtil.SetGroupToGroup(Mesh, extrudeGroup, 0);

            // 对选定区域进行重网格化优化
            RegionRemesher remesher = new RegionRemesher(Mesh, newRoi);

            // 提取顶部边界环的曲线，用于约束重网格化
            DCurve3 topCurve = MeshUtil.ExtractLoopV(Mesh, extrude.NewLoop.Vertices);
            DCurveProjectionTarget curveTarget = new DCurveProjectionTarget(topCurve);
            int[] topLoop = (int[])extrude.NewLoop.Vertices.Clone();
            remesher.Region.MapVerticesToSubmesh(topLoop);
            MeshConstraintUtil.ConstrainVtxLoopTo(remesher.Constraints, remesher.Mesh, topLoop, curveTarget);

            // 设置网格投影目标（保持在原始网格附近）
            DMeshAABBTree3 spatial = new DMeshAABBTree3(Mesh);
            spatial.Build();
            MeshProjectionTarget target = new MeshProjectionTarget(Mesh, spatial);
            remesher.SetProjectionTarget(target);

            // 执行重网格化
            bool performRemesh = true;
            if (performRemesh)
            {
                remesher.Precompute();
                remesher.EnableFlips = remesher.EnableSplits = remesher.EnableCollapses = true;
                remesher.MinEdgeLength = targetEdgeLen;
                remesher.MaxEdgeLength = 2 * targetEdgeLen;
                remesher.EnableSmoothing = true;
                remesher.SmoothSpeedT = 1.0f;

                // 多轮重网格化迭代
                for (int k = 0; k < 40; ++k)
                    remesher.BasicRemeshPass();

                // 关闭投影，进行最终平滑
                remesher.SetProjectionTarget(null);
                remesher.SmoothSpeedT = 0.25f;
                for (int k = 0; k < 10; ++k)
                    remesher.BasicRemeshPass();

                Debug.Assert(Mesh.CheckValidity());

                // 将重网格化结果回传到原始网格
                remesher.BackPropropagate();
            }

            // 平滑连接区域，消除网格畸变
            smooth_region(Mesh, remesher.Region.BaseBorderV, 3);
        }


        /// <summary>
        /// 对指定顶点周围N环内的区域进行局部平滑
        /// </summary>
        /// <param name="mesh">目标网格</param>
        /// <param name="vertices">中心顶点集合</param>
        /// <param name="nRings">扩展的环数</param>
        public static void smooth_region(DMesh3 mesh, IEnumerable<int> vertices, int nRings)
        {
            // 选择中心顶点的N环邻域三角形
            MeshFaceSelection roiTri = new MeshFaceSelection(mesh);
            roiTri.SelectVertexOneRings(vertices);
            for (int i = 0; i < nRings; ++i)
                roiTri.ExpandToOneRingNeighbours();
            roiTri.LocalOptimize(true, true);

            // 选择这些三角形包含的顶点
            MeshVertexSelection roiVerts = new MeshVertexSelection(mesh);
            roiVerts.SelectTriangleVertices(roiTri.ToArray());

            // 对选定顶点进行迭代平滑
            MeshIterativeSmooth meshSmooth = new MeshIterativeSmooth(mesh, roiVerts.ToArray(), true);
            meshSmooth.Alpha = 0.2f; // 平滑系数（较小值避免过度变形）
            meshSmooth.Rounds = 10;  // 平滑迭代次数
            meshSmooth.Smooth();
        }


        /// <summary>
        /// 平滑网格中的边界环：先平滑环本身，再平滑周围邻域
        /// </summary>
        /// <param name="mesh">目标网格</param>
        /// <param name="loop">边界环</param>
        /// <param name="nRings">周围邻域的环数</param>
        public static void smooth_loop(DMesh3 mesh, EdgeLoop loop, int nRings)
        {
            // 选择边界环顶点的N环邻域三角形
            MeshFaceSelection roiTri = new MeshFaceSelection(mesh);
            roiTri.SelectVertexOneRings(loop.Vertices);
            for (int i = 0; i < nRings; ++i)
                roiTri.ExpandToOneRingNeighbours();
            roiTri.LocalOptimize(true, true);

            // 选择邻域内的顶点（排除边界环顶点本身）
            MeshVertexSelection roiVerts = new MeshVertexSelection(mesh);
            roiVerts.SelectTriangleVertices(roiTri.ToArray());
            roiVerts.Deselect(loop.Vertices);

            // 初始化边界环平滑器和区域平滑器
            MeshLoopSmooth loopSmooth = new MeshLoopSmooth(mesh, loop);
            loopSmooth.Rounds = 1; // 每次迭代的环平滑步数

            MeshIterativeSmooth meshSmooth = new MeshIterativeSmooth(mesh, roiVerts.ToArray(), true);
            meshSmooth.Rounds = 1; // 每次迭代的区域平滑步数

            // 交替平滑环和区域，避免过度变形
            for (int i = 0; i < 10; ++i)
            {
                loopSmooth.Smooth();
                meshSmooth.Smooth();
            }
        }


        /// <summary>
        /// 边界环预处理：对边界环周围的局部区域进行重网格化，优化边界形状和拓扑
        /// </summary>
        /// <param name="mesh">目标网格</param>
        /// <param name="loop">边界环</param>
        /// <param name="targetEdgeLen">目标边长度</param>
        /// <param name="resultEdges">输出：处理后的边界环边集合（无序）</param>
        /// <param name="nRings">处理区域的环数</param>
        public static void cleanup_boundary(DMesh3 mesh, EdgeLoop loop, double targetEdgeLen, out List<int> resultEdges, int nRings = 3)
        {
            Debug.Assert(loop.IsBoundaryLoop()); // 确保输入是边界环

            // 选择边界环顶点的N环邻域三角形
            MeshFaceSelection roi = new MeshFaceSelection(mesh);
            roi.SelectVertexOneRings(loop.Vertices);
            for (int i = 0; i < nRings; ++i)
                roi.ExpandToOneRingNeighbours();
            roi.LocalOptimize(true, true);

            // 初始化区域重网格化器
            RegionRemesher remesher = new RegionRemesher(mesh, roi.ToArray());

            // 标记初始边界环的边，用于后续追踪
            int[] initLoopEdges = new int[loop.EdgeCount];
            Array.Copy(loop.Edges, initLoopEdges, loop.EdgeCount);
            remesher.Region.MapEdgesToSubmesh(initLoopEdges);
            MeshConstraintUtil.AddTrackedEdges(remesher.Constraints, initLoopEdges, 100); // 标记ID=100

            // 执行重网格化
            remesher.Precompute();
            remesher.EnableFlips = remesher.EnableSplits = remesher.EnableCollapses = true;
            remesher.MinEdgeLength = targetEdgeLen;
            remesher.MaxEdgeLength = 2 * targetEdgeLen;
            remesher.EnableSmoothing = true;
            remesher.SmoothSpeedT = 0.1f;

            // 多轮重网格化迭代
            for (int k = 0; k < nRings * 3; ++k)
                remesher.BasicRemeshPass();

            Debug.Assert(mesh.CheckValidity());

            // 提取标记的边界环边（重网格化后）
            List<int> newLoopEdges = remesher.Constraints.FindConstrainedEdgesBySetID(100);

            // 将重网格化结果回传到原始网格
            remesher.BackPropropagate();

            // 将处理后的边映射回原始网格
            resultEdges = MeshIndexUtil.MapEdgesViaVertexMap(
                remesher.ReinsertSubToBaseMapV,
                remesher.Region.SubMesh,
                remesher.BaseMesh,
                newLoopEdges
            );
        }
    }
}